from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from django.db.models import Q
from django.shortcuts import get_object_or_404
from system.models import Menu, RoleMenu, UserRole
from system.SysUtils.permission import permission_required
from .menus_serializers import (
    MenuSerializer, MenuOptionSerializer, MenuCreateSerializer, 
    MenuUpdateSerializer, MenuRouteSerializer, MenuFormSerializer
)


class MenuView(APIView):
    """菜单管理视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    @permission_required(["sys:menu:query"])
    def get(self, request, *args, **kwargs):
        """
        获取菜单列表（树形结构）
        
        查询参数:
        - keywords: 关键字(菜单名称)
        - status: 状态(1->显示；0->隐藏)
        """
        # 获取查询参数
        keywords = request.query_params.get('keywords', '')
        status = request.query_params.get('status')
        
        # 构建查询条件
        query = Q(parent_id=0)
        
        # 如果提供了关键字，则添加关键字过滤
        if keywords:
            # 使用递归CTE查询，找出所有包含关键字的菜单及其所有父菜单
            # 由于Django不直接支持递归CTE查询，这里采用先找出所有匹配关键字的菜单，
            # 然后递归向上找父菜单的方式来实现
            matching_menus = Menu.objects.filter(name__icontains=keywords)
            
            if matching_menus.exists():
                # 找出匹配关键字的菜单的所有父菜单ID
                parent_ids = set()
                for menu in matching_menus:
                    # 如果有tree_path字段，直接解析
                    if menu.tree_path:
                        parent_ids.update(int(pid) for pid in menu.tree_path.split(',') if pid)
                    
                    # 将当前菜单ID加入集合
                    parent_ids.add(menu.id)
                
                # 不应用parent_id=0筛选，而是查询所有符合条件的菜单
                query = Q(id__in=parent_ids) | Q(parent_id__in=parent_ids)
        
        # 获取状态筛选条件
        visible = None
        if status is not None:
            try:
                visible = int(status)
                # 注意：不在顶层过滤，而是在序列化时处理，以保持树形结构
            except ValueError:
                pass
        
        # 按排序字段和ID排序
        menus = Menu.objects.filter(query).order_by('sort', 'id')
        
        # 序列化
        context = {'visible': visible}
        serializer = MenuSerializer(menus, many=True, context=context)
        
        # 返回数据
        return Response({
            "code": "00000",
            "data": serializer.data,
            "msg": "获取菜单列表成功"
        })
    
    @permission_required(["sys:menu:add"])
    def post(self, request, *args, **kwargs):
        """
        创建菜单
        
        请求体:
        - 菜单表单对象
        """
        # 使用序列化器验证和创建菜单
        serializer = MenuCreateSerializer(data=request.data)
        
        if serializer.is_valid():
            # 创建菜单
            menu = serializer.save()
            
            # 序列化返回的菜单数据
            response_serializer = MenuSerializer(menu)
            
            # 返回成功响应
            return Response({
                "code": "00000",
                "data": response_serializer.data,
                "msg": "菜单创建成功"
            })
        else:
            # 返回验证错误信息
            return Response({
                "code": "A0400",
                "msg": serializer.errors
            }, status=400)
    
    @permission_required(["sys:menu:edit"])
    def put(self, request, *args, **kwargs):
        """
        更新菜单
        
        路径参数:
        - id: 菜单ID
        
        请求体:
        - 菜单表单对象
        """
        # 获取菜单ID
        menu_id = kwargs.get('id')
        
        # 获取菜单对象，如果不存在则返回404
        menu = get_object_or_404(Menu, id=menu_id)
        
        # 使用序列化器验证和更新菜单
        serializer = MenuUpdateSerializer(menu, data=request.data, partial=True)
        
        if serializer.is_valid():
            # 更新菜单
            updated_menu = serializer.save()
            
            # 序列化返回的菜单数据
            response_serializer = MenuSerializer(updated_menu)
            
            # 返回成功响应
            return Response({
                "code": "00000",
                "data": response_serializer.data,
                "msg": "菜单更新成功"
            })
        else:
            # 返回验证错误信息
            return Response({
                "code": "A0400",
                "msg": serializer.errors
            }, status=400)
    
    @permission_required(["sys:menu:delete"])
    def delete(self, request, *args, **kwargs):
        """
        删除菜单
        
        路径参数:
        - id: 菜单ID，多个以英文逗号(,)分割
        """
        # 获取菜单ID
        menu_id = kwargs.get('id')
        
        if not menu_id:
            return Response({
                "code": "A0400",
                "msg": "请指定要删除的菜单ID"
            }, status=400)
        
        # 处理多个ID的情况
        menu_ids = str(menu_id).split(',')
        
        # 转换为整数列表
        try:
            menu_ids = [int(mid) for mid in menu_ids if mid]
        except ValueError:
            return Response({
                "code": "A0400",
                "msg": "菜单ID格式不正确"
            }, status=400)
        
        if not menu_ids:
            return Response({
                "code": "A0400",
                "msg": "请指定要删除的菜单ID"
            }, status=400)
        
        # 查询要删除的菜单
        menus_to_delete = Menu.objects.filter(id__in=menu_ids)
        
        # 检查是否存在子菜单
        child_menus = Menu.objects.filter(parent_id__in=menu_ids)
        if child_menus.exists():
            return Response({
                "code": "A0400",
                "msg": "存在子菜单，无法删除"
            }, status=400)
        
        # 删除菜单
        count = menus_to_delete.count()
        menus_to_delete.delete()
        
        # 返回成功响应
        return Response({
            "code": "00000",
            "data": {},
            "msg": f"成功删除{count}个菜单"
        })


class MenuOptionsView(APIView):
    """菜单下拉选项视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    @permission_required(["sys:menu:query"])
    def get(self, request, *args, **kwargs):
        """
        获取菜单下拉选项（树形结构）
        
        查询参数:
        - onlyParent: 是否只查询父级菜单(1为菜单，2为目录，排除3为外链和4为按钮)
        """
        # 获取查询参数
        only_parent = request.query_params.get('onlyParent', 'false').lower() == 'true'
        
        # 查询顶级菜单
        root_menus = Menu.objects.filter(parent_id=0).order_by('sort', 'id')
        
        # 如果只查询父级菜单，则排除类型为3(外链)和4(按钮)的菜单
        if only_parent:
            root_menus = root_menus.exclude(type__in=[3, 4])
        
        # 序列化
        context = {'only_parent': only_parent}
        serializer = MenuOptionSerializer(root_menus, many=True, context=context)
        
        # 返回数据
        return Response({
            "code": "00000",
            "data": serializer.data,
            "msg": "一切ok"
        })


class MenuRoutesView(APIView):
    """菜单路由视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    def get(self, request, *args, **kwargs):
        """
        获取当前用户的菜单路由
        
        根据用户角色获取对应的菜单路由
        """
        # 获取当前用户ID
        user_id = request.user.id
        
        # 获取用户角色ID列表
        role_ids = UserRole.objects.filter(user_id=user_id).values_list('role_id', flat=True)
        
        # 获取角色对应的菜单ID列表
        menu_ids = RoleMenu.objects.filter(role_id__in=role_ids).values_list('menu_id', flat=True).distinct()
        
        # 查询顶级菜单
        root_menus = Menu.objects.filter(
            Q(parent_id=0) & Q(id__in=menu_ids)
        ).order_by('sort', 'id')
        
        # 序列化菜单路由
        serializer = MenuRouteSerializer(
            root_menus, 
            many=True, 
            context={'menu_ids': menu_ids}
        )
        
        # 返回成功响应
        return Response({
            "code": "00000",
            "data": serializer.data,
            "msg": "获取菜单路由成功"
        })


class MenuFormView(APIView):
    """菜单表单视图"""
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    
    @permission_required(["sys:menu:edit"])
    def get(self, request, *args, **kwargs):
        """
        获取菜单表单数据
        
        路径参数:
        - id: 菜单ID
        """
        # 获取菜单ID
        menu_id = kwargs.get('id')
        
        # 获取菜单对象，如果不存在则返回404
        menu = get_object_or_404(Menu, id=menu_id)
        
        # 序列化菜单表单数据
        serializer = MenuFormSerializer(menu)
        
        # 返回成功响应
        return Response({
            "code": "00000",
            "data": serializer.data,
            "msg": "一切ok"
        })
